package image.mapper;

import image.PixelImage;
import image.color.Color_Float;
import math.mathExtended.MathExtended;

/**
 *
 * Fully Tested: No
 * Fully Documented: No
 * Created: 23-May-2012
 * Last Updated: 23-May-2012
 *
 * @author Shimu Wu
 */
public class SquareKernelMapper implements PixelImageMapper {

    private final float[] kernel;

    private final int maxX;

    private final int maxY;

    private final int midX;

    private final int midY;

    private final String name;

    public SquareKernelMapper(int maxX, int maxY, float[] kernel, String name) {
        this.maxX = maxX;
        this.maxY = maxY;
        this.midX = maxX / 2;
        this.midY = maxY / 2;
        if (kernel == null) {
            this.kernel = new float[maxX * maxY];
            for (int i = 0; i < this.kernel.length; i++) {
                this.kernel[i] = 0f;
            }                    
        } else {
            this.kernel = kernel;        
        }
        this.name = name;
    }

    public int getColumns() {
        return maxX;
    }

    public int getRows() {
        return maxY;
    }

    /**
     * Returns a copy of this kernel as a double array.
     * @return 
     */
    public float[] getKernel() {
        return kernel;
    }

    @Override
    public int process(int originalX, int originalY,
            PixelImage original) {

        if (!MathExtended.bounded(originalX, midX, original.getWidth()
                - midX - 1) || !MathExtended.bounded(originalY, midY,
                original.getHeight() - midY - 1)) {
            return original.get(originalX, originalY);
        }

        Color_Float ac = new Color_Float(0, 0, 0), temp; // accumulator
        int kernelIndex = 0;

        for (int y = -midY; y <= midY; y++) {
            for (int x = -midX; x <= midX; x++) {
                temp = new Color_Float(original.get(originalX + x,
                        originalY + y));
                temp.scale(kernel[kernelIndex]);
                ac.add(temp);
                kernelIndex++;
            }
        }
        ac.clamp();

        return ac.intRep();
    }

    /**
     * Returns the name of this mapper.
     * @return 
     */
    public String getName() {
        return this.name;
    }

    /**
     * Returns a String that can be used to save this mapper to a file or 
     * sent over a network.
     * @return 
     */
    public String getSerizationString() {
        StringBuilder b = new StringBuilder();
        for(float value : this.kernel) {
            b.append(Float.toString(value));
            b.append(" ");
        }
        return String.format("%d %d %s %s", maxX, maxY, b.toString(), name);
    }
    
    /**
     * Returns a String of the form: <br /> 
     * name (row by column)
     * @return 
     */
    @Override
    public String toString() {
        return String.format("%s (%d by %d)", name, maxX, maxY);
    }
}
